package com.york.tinyrpc.proto.proxy;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.york.tinyrpc.proto.model.TinyRpcRequest;
import com.york.tinyrpc.proto.model.TinyRpcResponse;
import com.york.tinyrpc.proto.serializer.JdkSerializer;
import com.york.tinyrpc.proto.serializer.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 基于JDK的动态代理实现
 * 灵活处理所有接口类型的代理对象去执行
 */
public class ServiceHandler implements InvocationHandler {

    private static final Logger log = LoggerFactory.getLogger(ServiceHandler.class);


    /**
     * 调用代理
     *
     * @param proxy  代理对象
     * @param method 被代理对象的方法
     * @param args   被代理对象方法的参数
     * @return Object 代理对象运行结果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 指定序列化器
        Serializer serializer = new JdkSerializer();

        // 构造请求，TinyRpcRequest实体类由@Builder注解，编译会生成建造者模式，可以一些列...的方式生成对象
        TinyRpcRequest rpcRequest = TinyRpcRequest.builder()
                .serviceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();

        try {
            // 将请求序列化，通过网络传输到服务提供方
            byte[] bodyBytes = serializer.serialize(rpcRequest);

            // todo proto版本：发送请求，硬编码方式（需要使用注册中心和服务发现机制解决）
            try (HttpResponse httpResponse = HttpRequest.post("http://localhost:8000")
                    .body(bodyBytes)
                    .execute()) {
                byte[] result = httpResponse.bodyBytes();
                // 反序列化调用结果为统一结果
                TinyRpcResponse rpcResponse = serializer.deserialize(result, TinyRpcResponse.class);
                Object data = rpcResponse.getData();
                log.info("TinyRpc调用成功 rpcResponse:{}", data);
                return data;
            }
        } catch (IOException e) {
            log.error("TinyRpc调用失败:{}", e.getMessage());
        }

        // 如果执行到这还没有return说明没有调用成功
        return null;
    }
}
